using System;

namespace ITDM
{
    public class Crc32
    {
        uint[] table;

        public static string ChecksumString(uint crc)
        {
            byte[] b = { 0, 0, 0, 0 };
            for (int i = 0; i < 4; i++)
            {
                b[i] = (byte)(crc % 256);
                crc = crc >> 8;
            }
            return b[3].ToString("X2") + b[2].ToString("X2") + b[1].ToString("X2") + b[0].ToString("X2");
        
        }

        public uint ComputeChecksum(string path)
        {
            // Use 1 MB buffer as default
            return ComputeChecksum(path, 0x100000);
        }
   
        public uint ComputeChecksum(string path, int buffer_size)
        {
            byte[] buffer = new byte[buffer_size];
            uint sum = 0;
            long file_position = 0;
            System.IO.FileStream fs = System.IO.File.OpenRead(path);
            while (file_position < fs.Length)
            {
                int bytes_read = fs.Read(buffer, 0, buffer_size);
                file_position += bytes_read;
                sum = ComputeChecksum(buffer, bytes_read,sum);
            }
            fs.Close();
            return sum;           
        }


        public uint ComputeChecksum(byte[] bytes)
        {
            uint sum = 0x0;
            return ComputeChecksum(bytes,bytes.Length, sum);
        }

        private uint ComputeChecksum(byte[] bytes, int buffer_size, uint sum)
        {
            sum = ~sum;
            for (int i = 0; i < buffer_size; i++)
            {
                byte index = (byte)(((sum) & 0xff) ^ bytes[i]);
                sum = (uint)((sum >> 8) ^ table[index]);
            }
            return ~sum;
        }


        public Crc32()
        {
            uint poly = 0xedb88320;
            table = new uint[256];
            uint temp = 0;
            for (uint i = 0; i < table.Length; i++)
            {
                temp = i;
                for (int j = 8; j > 0; j--)
                {
                    if ((temp & 1) == 1)
                    {
                        temp = (uint)((temp >> 1) ^ poly);
                    }
                    else
                    {
                        temp >>= 1;
                    }
                }
                table[i] = temp;
            }
        }
    }
}